﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Threading;

namespace 温湿度和颗粒度监控测试.Common.传感器
{
    public class 温湿度记颗粒度传感器: IDisposable
    {
        public 温湿度记颗粒度传感器()
        {
            serialPort = new SerialPort();
        }

        /// <summary>
        /// 设备Id
        /// </summary>
        public byte DeviceId { get; set; }

        /// <summary>
        /// 使用的串口
        /// </summary>
        private SerialPort serialPort;

        /// <summary>
        /// 串口名
        /// </summary>
        public string PortName { get; set; }

        /// <summary>
        /// 波特率
        /// </summary>
        public int BaudRate { get; set; } = 9600;

        /// <summary>
        /// 数据位
        /// </summary>
        public int DataBits { get; set; } = 8;

        /// <summary>
        /// 校验位 默认为None
        /// </summary>
        public Parity Parity { get; set; } = Parity.None;

        /// <summary>
        /// 停止位 默认为One
        /// </summary>
        public StopBits StopBits { get; set; } = StopBits.One;

        /// <summary>
        /// 读串口锁
        /// </summary>
        private bool readLock = false;

        /// <summary>
        /// 打开串口
        /// </summary>
        private void Open()
        {
            if (serialPort == null) throw new ApplicationException("serialPort不能为空");
            if (serialPort.IsOpen) return;

            serialPort.PortName = !string.IsNullOrEmpty(PortName) ? PortName : throw new ApplicationException("缺少参数PortName，无法打开串口");
            serialPort.BaudRate = BaudRate;
            serialPort.DataBits = DataBits;
            serialPort.Parity = Parity;
            serialPort.StopBits = StopBits;
            serialPort.Open();
        }

        public double 获取温度值(byte deviceId, int readDelay = 150)
        {
            if (serialPort == null) throw new ApplicationException("未打开串口");
            if (!serialPort.IsOpen) Open();

            byte[] message = new byte[8];
            message[0] = deviceId;
            message[1] = 0x03;  // 读取寄存器
            message[2] = 0x03;
            message[3] = 0x00;  // 寄存器地址
            message[4] = 0x00;
            message[5] = 0x01;  // 寄存器数量
            byte[] crc16Value = Modbus.ModbusSerialPort.CRC16_MODBUS_Formated(message.Take(6).ToList());
            message[6] = crc16Value[0];
            message[7] = crc16Value[1];

            while (readLock) { }

            readLock = true;
            serialPort.Write(message, 0, message.Length);
            Thread.Sleep(readDelay);
            int n = serialPort.BytesToRead;
            byte[] receiveMessage = new byte[n];

            serialPort.Read(receiveMessage, 0, n);
            Thread.Sleep(readDelay);
            readLock = false;

            #region 原先报文不对的逻辑
            //// 解析收到的报文内容
            //if (receiveMessage.Length < 7) throw new ApplicationException($"接收到的报文长度与预设不相符, 报文长度为{receiveMessage.Length}");
            #endregion

            // 解析收到的报文内容
            if (receiveMessage.Length < 7) return -1000;

            Int16 温度 = BitConverter.ToInt16(new byte[] { receiveMessage[4], 0x00 }, 0);
            if (receiveMessage[3] == 0xFF)  // 温度小于0
                温度 -= 256;
            return 温度 * 0.1;
        }

        public double 获取湿度值(byte deviceId, int readDelay = 150)
        {
            if (serialPort == null) throw new ApplicationException("未打开串口");
            if (!serialPort.IsOpen) Open();

            byte[] message = new byte[8];
            message[0] = deviceId;
            message[1] = 0x03;  // 读取寄存器
            message[2] = 0x03;
            message[3] = 0x01;  // 寄存器地址
            message[4] = 0x00;
            message[5] = 0x01;  // 寄存器数量
            byte[] crc16Value = Modbus.ModbusSerialPort.CRC16_MODBUS_Formated(message.Take(6).ToList());
            message[6] = crc16Value[0];
            message[7] = crc16Value[1];

            while (readLock) { }

            readLock = true;
            serialPort.Write(message, 0, message.Length);
            Thread.Sleep(readDelay);
            int n = serialPort.BytesToRead;
            byte[] receiveMessage = new byte[n];

            serialPort.Read(receiveMessage, 0, n);
            Thread.Sleep(readDelay);
            readLock = false;

            // 解析收到的报文内容
            //if (receiveMessage.Length < 7) throw new ApplicationException($"接收到的报文长度与预设不相符, 报文长度为{receiveMessage.Length}");
            if (receiveMessage.Length < 7) return -1000;

            Int16 湿度 = BitConverter.ToInt16(receiveMessage.Skip(3).Take(2).Reverse().ToArray(), 0);
            return 湿度 * 0.1;
        }

        public int 获取AM1050的PM05颗粒度(byte deviceId, int readDelay = 150)
        {
            if (serialPort == null) throw new ApplicationException("未打开串口");
            if (!serialPort.IsOpen) Open();

            byte[] message = new byte[8];
            message[0] = deviceId;
            message[1] = 0x03;  // 读取寄存器
            message[2] = 0x00;
            message[3] = 0x12;  // 寄存器地址
            message[4] = 0x00;
            message[5] = 0x02;  // 寄存器数量
            byte[] crc16Value = Modbus.ModbusSerialPort.CRC16_MODBUS_Formated(message.Take(6).ToList());
            message[6] = crc16Value[0];
            message[7] = crc16Value[1];

            while (readLock) { }

            readLock = true;
            serialPort.Write(message, 0, message.Length);
            Thread.Sleep(readDelay);
            int n = serialPort.BytesToRead;
            byte[] receiveMessage = new byte[n];

            serialPort.Read(receiveMessage, 0, n);
            Thread.Sleep(readDelay);
            readLock = false;

            // 解析收到的报文内容
            //if (receiveMessage.Length < 7) throw new ApplicationException($"接收到的报文长度与预设不相符, 报文长度为{receiveMessage.Length}");
            if (receiveMessage.Length < 7) return -1000;

            int 颗粒度 = BitConverter.ToInt32(receiveMessage.Skip(3).Take(4).Reverse().ToArray(), 0);
            return 颗粒度;
        }

        public int 获取OPC6030M的PM05(byte deviceId, int readDelay = 150)
        {
            if (serialPort == null) throw new ApplicationException("未打开串口");
            if (!serialPort.IsOpen) Open();

            byte[] message = new byte[8];
            message[0] = deviceId;
            message[1] = 0x04;  // 读取输入寄存器
            message[2] = 0x00;
            message[3] = 0x05;  // 寄存器地址
            message[4] = 0x00;
            message[5] = 0x02;  // 寄存器数量
            byte[] crc16Value = Modbus.ModbusSerialPort.CRC16_MODBUS_Formated(message.Take(6).ToList());
            message[6] = crc16Value[0];
            message[7] = crc16Value[1];

            while (readLock) { }

            readLock = true;
            serialPort.Write(message, 0, message.Length);
            Thread.Sleep(readDelay);
            int n = serialPort.BytesToRead;
            byte[] receiveMessage = new byte[n];

            serialPort.Read(receiveMessage, 0, n);
            Thread.Sleep(readDelay);
            readLock = false;

            // 解析收到的报文内容
            //if (receiveMessage.Length < 7) throw new ApplicationException($"接收到的报文长度与预设不相符, 报文长度为{receiveMessage.Length}");
            if (receiveMessage.Length < 7) return -1000;

            int 颗粒度 = BitConverter.ToInt32(receiveMessage.Skip(3).Take(4).Reverse().ToArray(), 0);
            return 颗粒度;
        }


        public int 获取攀藤的PM05(byte deviceId, int readDelay = 150)
        {
            if (serialPort == null) throw new ApplicationException("未打开串口");
            if (!serialPort.IsOpen) Open();

            byte[] message = new byte[8];
            message[0] = deviceId;
            message[1] = 0x03;  // 读取寄存器
            message[2] = 0x00;
            message[3] = 0x00;  // 寄存器地址
            message[4] = 0x00;
            message[5] = 0x11;  // 寄存器数量
            byte[] crc16Value = Modbus.ModbusSerialPort.CRC16_MODBUS_Formated(message.Take(6).ToList());
            message[6] = crc16Value[0];
            message[7] = crc16Value[1];

            while (readLock) { }

            readLock = true;
            serialPort.Write(message, 0, message.Length);
            Thread.Sleep(readDelay);
            int n = serialPort.BytesToRead;
            byte[] receiveMessage = new byte[n];

            serialPort.Read(receiveMessage, 0, n);
            Thread.Sleep(readDelay);
            readLock = false;

            // 解析收到的报文内容
            //if (receiveMessage.Length < 7) throw new ApplicationException($"接收到的报文长度与预设不相符, 报文长度为{receiveMessage.Length}");
            if (receiveMessage.Length < 7) return -1000;


            UInt16 颗粒度 = BitConverter.ToUInt16(receiveMessage.Skip(23).Take(2).Reverse().ToArray(), 0);
            颗粒度 = (UInt16)(颗粒度 * 10);
            return 颗粒度;
        }

        public void Close()
        {
            if (serialPort != null) return;

            serialPort.Close();
        }

        public void Dispose()
        {
            if (serialPort == null) return;

            serialPort.Close();
            serialPort.Dispose();
        }
    }
}
